fix(compiler): preserve anchor semantics across references#589
Merged
zharinov merged 3 commits intoJul 16, 2026
Conversation
zharinov
marked this pull request as ready for review
July 16, 2026 17:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Structural extraction now preserves matching semantics around soft and exact anchors. Inline patterns, grouped patterns, and equivalent definition references have the same match set across nullable paths, alternations, quantifiers, recursion, captures, and grammar fields.
Previously, lowering reduced nullable control flow to consuming and empty outcomes. That lost distinctions such as a pending anchor or the namedness of the previous consumer before control crossed a reference boundary.
Reference output remains opaque. This change preserves structural behavior without exposing captures from an uncollected reference.
Boundary semantics
The compiler now computes a path-sensitive
BoundaryRelationfor each pattern. Recursive definitions reach a least fixed point per dependency component.The relation tracks:
Consecutive anchors tighten their constraint, so an exact anchor can never be loosened by a later soft anchor. Quantifier loops admit only consuming iterations, while
?and*retain their zero-iteration paths.Lowering maps descriptive outcomes onto an eight-member operational exit universe. Each definition specialization exposes only its reachable ports through a dense local
PortIdsignature. Missing ports mean failure and never fall back to another continuation.Navigation and grammar fields are carried through a compositional
EntryObligation. Empty wrappers and nullable prefixes forward the obligation until the first actual consumer discharges it exactly once. Empty paths and later followers do not inherit the field.Definitions may now export a boundary-anchor requirement for their caller to satisfy. They remain reusable fragments but are not treated as contextless entry points. Validation reports only anchors that remain without context after definition composition.
Calls and runtime
Ordinary, routed, nullable, and boundary-aware references now use one semantic call operation with:
The bytecode format is version 12 and uses:
0x6 Call1for one-port calls0x7 CallNfor calls with two to eight ports0x8 Returnwith a callee-local portThe loader verifies call arity, dense return ports, target instruction boundaries, entry ownership, navigation and field contracts, cursor behavior per port, and reserved encoding space.
Runtime frames store only the immutable call-site address.
Return(port)pops that frame and resolves(call_site, port)through the call’s continuation map. This preserves cactus-stack restoration and retry behavior without copying a maximum-sized continuation array into ordinary frames.Generated Rust matchers use the same call-site return model as the bytecode VM.
Validation
Regression coverage now includes:
A proof-oriented unit test also checks that the operational exit quotient preserves every future anchor observation represented by the descriptive boundary relation.